/**
 * @Description PointMonthTimer.java
 * @author xu_cc [18724000100@163.com]
 * @date 创建时间：2017年10月25日 上午11:58:18
 */
package com.solution.admin.point.timer;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.solution.admin.point.constants.PointConstants.TimerSwitch;
import com.solution.admin.point.entity.PointMonthEntity;
import com.solution.admin.point.service.PointMonthService;
import com.solution.common.config.PublicConfigUtil;
import com.solution.common.utils.DateUtils;

/**
 * 积分月度统计定时任务（月初生成期初积分、月中每日统计本月积分增减情况）
 * @author xu_cc
 * @date 创建时间：2017年10月25日 上午11:58:24
 */
@Component
public class PointMonthTimer implements InitializingBean {

    private Logger logger = LoggerFactory.getLogger(PointMonthTimer.class);

    @Autowired
    PointMonthService pointMonthService;

    /** 期初积分生成任务开关 key */
    static final String POINT_MONTH_SWITCH = "timer.pointMonth.switch";
    /** 期初积分生成任务执行日期key */
    static final String POINT_MONTH_BEGIN_POINT_DAY = "timer.pointMonth.beginPointDay";
    /** 期初积分生成任务执行时间key */
    static final String POINT_MONTH_BEGIN_POINT_TIME = "timer.pointMonth.beginPointTime";
    /** 月度积分之每日积分统计时间key */
    static final String POINT_MONTH_CALC_POINT_DAILY_TIME = "timer.pointMonth.pointCalcDailyTime";

    /**
     * 定时任务
     * 
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     * @Title: afterPropertiesSet
     * @throws Exception
     * @author xu_cc
     * @throws Exception exception
     * @Date 创建时间：2017年10月25日 下午6:23:52
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        // 获取任务开关
        String timerSwitch = PublicConfigUtil.readConfig(POINT_MONTH_SWITCH);
        if (TimerSwitch.OFF.equals(timerSwitch)) {
            // 如果开关关闭，则不执行定时任务
            return;
        } else if (TimerSwitch.ON.equals(timerSwitch)) {
            // 线程一：每月1号凌晨，生成所有客户的期初积分（所有客户积分）
            // 一天的毫秒数
            long oneDay = 24 * 60 * 60 * 1000;
            // 每天几点执行
            String firstTimer = PublicConfigUtil.readConfig(POINT_MONTH_BEGIN_POINT_TIME);
            // 计算初始延迟的毫秒数
            long firstInitDelay = DateUtils.getTimeMillis(firstTimer) - System.currentTimeMillis();
            // 执行线程(月初积分月度期初积分生成)
            Runnable firstRunnable = new Runnable() {
                @Override
                public void run() {
                    logger.error("*****************开始定时任务：生成每月期初积分*******************");
                    Calendar ca = Calendar.getInstance();
                    int day = ca.get(Calendar.DATE);
                    // 从配置文件中获取任务执行日期
                    int configDay = Integer.parseInt(PublicConfigUtil.readConfig(POINT_MONTH_BEGIN_POINT_DAY));
                    if (day != configDay) {
                        logger.error("今天不是 " + configDay + " 号，无需生成期初积分信息，今天是：" + day + " 日");
                        return;
                    } else {
                        // 当前月份
                        SimpleDateFormat monthFormat = new SimpleDateFormat("yyyyMM");
                        String month = monthFormat.format(new Date());
                        Map<String, Object> param = new HashMap<String, Object>();
                        param.put("month", month);
                        List<PointMonthEntity> list = pointMonthService.listPointMonth(param);
                        if (null != list && list.size() > 0) {
                            // 本月已经生成了，不需要再次生成了
                            logger.error("本月已经生成了，不需要再次生成了！月份：" + month);
                            return;
                        } else {
                        	// 将上个月用户积分余额添加到其实表中
                            int rows = pointMonthService.insertMonthBegin(month);
                            logger.error("生成月度积分期初积分信息：" + rows + "条！");
                        }
                    }
                    logger.error("*****************定时任务结束：生成每月期初积分*******************");
                }
            };
            
            // 线程二：每天统计所有客户增加积分、使用积分，计算期末积分
            // 每天几点执行
            String timer = PublicConfigUtil.readConfig(POINT_MONTH_CALC_POINT_DAILY_TIME);
            // 计算初始延迟的毫秒数
            long initDelay = DateUtils.getTimeMillis(timer) - System.currentTimeMillis();
            // 执行线程(月中每日统计)
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    logger.error("*****************开始执行月度积分统计定时任务*******************");
                    try {
                        // 当前月份
                        SimpleDateFormat monthFormat = new SimpleDateFormat("yyyyMM");
                        String month = monthFormat.format(new Date());
                        List<PointMonthEntity> list = pointMonthService.getPointByMonth(month);
                        if (null != list && list.size() > 0) {
                            // 计算期末积分
                            List<PointMonthEntity> newList = new ArrayList<PointMonthEntity>();
                            BigDecimal endPoint = BigDecimal.ZERO;
                            for (PointMonthEntity pointMonth : list) {
                                // 期末积分 = 期初积分 + 订单累加积分 + 签到累加积分 + 人工增加积分 -
                                // 人工核减积分 -
                                // 已用积分
                                endPoint = pointMonth.getBeginPoint().add(pointMonth.getOrderPoint()).add(pointMonth.getSignPoint())
                                        .add(pointMonth.getManualAddPoint()).subtract(pointMonth.getManualReducePoint())
                                        .subtract(pointMonth.getUsedPoint());
                                pointMonth.setEndPoint(endPoint);
                                newList.add(pointMonth);
                            }
                            int rows = pointMonthService.insertList(month, newList);
                            logger.error("插入月度统计信息：" + rows + "条！");
                        } else {
                            logger.error("获取客户月度统计信息失败！");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    logger.error("*****************月度积分统计定时任务执行结束*******************");
                }
            };
            ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
            // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
            // 期初积分任务加入线程池, firstInitDelay 为当前时间和跑批之间的时间差，延迟这么久执行，然后执行间隔是一天
            service.scheduleAtFixedRate(firstRunnable, firstInitDelay, oneDay, TimeUnit.MILLISECONDS);
            // 月中每日积分统计任务加入线程池
            service.scheduleAtFixedRate(runnable, initDelay, oneDay, TimeUnit.MILLISECONDS);
        } else {
            logger.error("未知的定时任务开关值，请输入 on/off ");
        }
    }

}
